/*
 * serverCondition.cc
 *
 *  Created on: Jun 29, 2011
 *      Author: peckb1
 */

#include "serverCondition.h"

ServerCondition::ServerCondition(char* name, int machineOwner) {
    isDeleted = FALSE;
    isScheduledForDeletion = FALSE;
    waitingLock = NULL;
    CVWaitQueue = new List();
    CVName = new char[strlen(name)];
    strcpy(CVName, name);
    owningMachine = machineOwner;
}

ServerCondition::~ServerCondition() {
    delete CVWaitQueue;
}

MailAddress*
ServerCondition::Wait(MailAddress* address, ServerLock* lock) {
    MailAddress* personWaiting = NULL;

    if(address->MachineId() != owningMachine) {
        printf("ERROR: Machine %i tried to Wait on a CV (%s) owned by Machine %i.\n", address->MachineId(), CVName, owningMachine);
    } else {
        if(waitingLock == NULL) {
            waitingLock = lock;
        }

        if(waitingLock != lock) {
            printf("ERROR: Machine %i tried to wait on a Lock that this CV is not set to wait on.\n", address->MachineId());
        } else {
            CVWaitQueue->Append(address);
            personWaiting = lock->Release(address);
        }
    }

    return personWaiting;
}


MailAddress*
ServerCondition::Signal(MailAddress* address, ServerLock* lock) {
    MailAddress* wokenAddress = NULL;
    if(address->MachineId() != owningMachine) {
        printf("ERROR: Machine %i tried to Signal a CV (%s) owned by Machine %i.\n", address->MachineId(), CVName, owningMachine);
    } else {
        if(!CVWaitQueue->IsEmpty() && lock == waitingLock) {
            wokenAddress = (MailAddress*)CVWaitQueue->Remove();
            lock->Acquire(wokenAddress);

            if(!lock->isHeldByCurrentUser(wokenAddress)) {
                wokenAddress = NULL;
            }

            if(CVWaitQueue->IsEmpty()) {
                waitingLock = NULL;
                if(IsScheduledForDeletion()) {
                    isDeleted = TRUE;
                }
            }
        }
    }

    return wokenAddress;
}


List*
ServerCondition::Broadcast(MailAddress* address, ServerLock* lock) {
    List* manyToWake = new List();
    if(address->MachineId() != owningMachine) {
        printf("ERROR: Machine %i tried to Broadcast to a CV (%s) owned by Machine %i.\n", address->MachineId(), CVName, owningMachine);
    } else {
        while(!CVWaitQueue->IsEmpty()) {
            MailAddress* personWoke = Signal(address, lock);
            if(personWoke != NULL) {
                manyToWake->Append(personWoke);
            }
        }
    }

    return manyToWake;
}


bool
ServerCondition::DestroyCV(MailAddress* address) {
    bool success = FALSE;

    if(address->MachineId() != owningMachine) {
        printf("ERROR: Machine %i tried to Destroy a CV (%s) owned by Machine %i.\n", address->MachineId(), CVName, owningMachine);

    } else {
        if(CVWaitQueue->IsEmpty()) {
            isDeleted = TRUE;
        } else {
            isScheduledForDeletion = TRUE;
        }
        success = TRUE;
    }
    return success;
}


bool
ServerCondition::IsDeleted() {
    return isDeleted;
}
bool
ServerCondition::IsScheduledForDeletion() {
    return isScheduledForDeletion;
}

char*
ServerCondition::GetName() {
    return CVName;
}
